%%%-------------------------------------------------------------------
%%% @author wukai
%%% @copyright (C) 2017, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 20. 十二月 2017 20:18
%%%-------------------------------------------------------------------
-module(retain_server).
-author("wukai").

-behaviour(gen_server).

-define(RETTAIN_MSG, retain).
%% API %% 主题 %%mqtt消息 %%创建消息
-record(retain, {topic, msg, update_time, from_client}).
%% API
-export([start_link/0]).
-export([cre_tab/0]).
-export([retain_send/2]).
-export([retain_save/3]).
-export([retain_clean/1]).
-export([wrap_retain/3]).

-export([init/1,
  handle_call/3,
  handle_cast/2,
  handle_info/2,
  terminate/2,
  code_change/3]).

-define(SERVER, ?MODULE).

-record(state, {}).

start_link() ->
  gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).

init([]) ->
  {ok, #state{}}.
handle_call(_Request, _From, State) ->
  {reply, ok, State}.
handle_cast({send,Topic,Pid}, State) ->
  send(Topic,Pid),
  {noreply, State};
handle_cast({save,Client,Topic,Pub}, State) ->
  save(wrap_retain(Client,Topic,Pub)),
  {noreply, State};
handle_cast({delete,Topic}, State) ->
  delete(Topic),
  {noreply, State};
handle_cast(_Request, State) ->
  {noreply, State}.
handle_info(_Info, State) ->
  {noreply, State}.

terminate(_Reason, _State) ->
  ok.

code_change(_OldVsn, State, _Extra) ->
  {ok, State}.


cre_tab() ->
  mnesia:create_table(?RETTAIN_MSG,
    [
      {storage_properties,
        [{dets, [{auto_save, 3000}]}]},
      {disc_copies, [node() | nodes()]},
      {attributes, record_info(fields, retain)},
      {type, set}
    ]
  ).

save(Item) ->
  case mnesia:transaction(fun() -> mnesia:write(Item) end) of
    {atomic, Val} ->log:log("save retrain ok ~p", [Val]), ok;
    {aborted,R} ->log:log("save retrain error ~p", [R]),error
  end.

delete(Topic) ->

  F = fun() -> mnesia:delete({?RETTAIN_MSG, Topic}) end,
  case mnesia:transaction(F) of
    ok -> log:log("delete retain msgs topic is  ~p", [Topic]);
    _ -> log:log("look retian msg error ~p")
  end.

send(Topic,Pid) ->
  F = fun() -> mnesia:read({?RETTAIN_MSG, Topic}) end,
  case mnesia:transaction(F) of
    {atomic, ResultOfFun} ->
      lists:foreach(fun(E) ->
            mqtt_process:send_msg(Pid,E#retain.msg) end, ResultOfFun);
    {aborted, Reason} -> log:log("send retain msg error ~p", [Reason]);
    Other -> log:log("send retain msg error ~p", [Other])
  end.

retain_send(Topic,Pid)-> gen_server:cast(retain_server,{send,Topic,Pid}).
retain_save(Client,Topic,Pub)-> gen_server:cast(retain_server,{save,Client,Topic,Pub}).
retain_clean(Topic)-> gen_server:cast(retain_server,{delete,Topic}).

wrap_retain(Client,Topic,Item)->
  #retain{from_client =Client,  topic =Topic, msg = Item, update_time = time_utils:timestamp()}.